# _*_ coding : utf-8 _*_

from random import shuffle
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
import pandas as pd
import time
import random
import itertools
from math import radians, cos, sin, asin, sqrt
import sys
import copy
import time


# 选择摧毁算子
def selectAndUseDestroyOperator(destroyWeightF, currentSolution, stepF):  # select and use destroy operators
    destroyOperatorF = -1  # 初始化destroyOperator的值为-1，后面可以将destoryOperator打印出来看看调用了哪个摧毁算子
    print("current solution是", currentSolution)
    sol = copy.deepcopy(currentSolution)
    destroyRouletteF = np.array(destroyWeightF).cumsum()  # destroyRoulette是destroyWeight的累加
    # print("destroyWeight是", destroyWeight)
    # print("destroyRoulette是", destroyRoulette)
    # print("r摧毁是", r)
    i=0
    destroyOperatorF = i  # 初始化摧毁因子为1
    print("destroyOperator=", destroyOperatorF)
    sol, removed = destroyF1(sol, stepF)  # 将随机将两个F类型订单对应的节点丢出来 ，removed对应的是被丢出来的两对节点
    destroyUseTimesF[i] += 1
    # print("destroyUseTimes=", destroyUseTimes)
    return sol, removed, destroyOperatorF


# 选择修复算子
def selectAndUseRepairOperator(repairWeightF, destroyedSolution, removeList):  # select and use repair operators
    print("destroyedSolution是", destroyedSolution)
    print("removeList是", removeList)
    repairOperatorF = -1  # 初始化修复因子为-1，后面可以将repairOperator打印出来看看调用了哪个修复算子
    repairRouletteF = np.array(repairWeightF).cumsum()  # 将repairWeight累加至repairRoulette
    # print("repairWeight是", repairWeight)
    # print("repairRoulette是", repairRoulette)

    # print("r修复是", r)
    repairOperatorF = 0
    i=0
    print("repairOperatorF=", repairOperatorF)
    destroyedSolution, removeList = repairF1(destroyedSolution, removeList)
    repairUseTimesF[i] += 1
    # print("repairUseTimes=", repairUseTimes)

    return destroyedSolution, repairOperatorF, removeList


# 贪婪生成排班路径
def genF(ways, pool):# 贪婪重建算子
    for influencer in range(pool):#遍历每个主播
        if ((influencer+1)%10==0):
            print("="*30)
        bestbestway=[]#记录每次插入最优的解
        bestbestmoney=-float("inf")#记录每次插入最优的收入

        for eachone in range(len(ways)) :#遍历每个直播间
            way=ways[eachone]
            if eachone!=0:
                if way==[] and preHouse==[]:#若当前播间为空，则后续也必定为空
                        break
            #这种情况下可以以一种思路插
            if way==[]:
                #考虑不化妆直接插
                tempways=copy.deepcopy(ways)
                tempattr = []  # 主播的状态
                tempattr.append(0)
                tempattr.append(0)
                tempattr.append(8)
                tempways[eachone].append(tempattr)#记录不化妆情况下最好的插入路径
                tempmoney=moneySum(tempways)#记录不化妆情况下最好的插入收入
                # print("tempways=",tempways)

                #考虑化完妆再插
                besttemptempway=[]#记录化妆情况下最好的插入路径
                besttemptempmoney=-float("inf")#记录化妆情况下最好的插入收入
                for whichone in range(dresserNumber):#遍历所有化妆师
                    for when in range(20):#遍历化妆师的所有工作时间结点
                        if when==10 or when==11:#避开化妆师午休时间
                            continue
                        dressWhen=7+0.5*when#化妆时间
                        temptempattr=[]
                        temptempattr.append(whichone+1)
                        temptempattr.append(dressWhen)
                        temptempattr.append(0)
                        if dressWhen==7.0:
                            for whenLive in range(10):
                                liveWhen=8+0.5*whenLive
                                temptempattr[2]=liveWhen
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].append(temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney>besttemptempmoney:
                                    besttemptempmoney=temptempmoney
                                    besttemptempway=copy.deepcopy(temptempways)
                                # print("besttemptempway=", besttemptempway)
                        else:
                            for whenLive in range(11):
                                if whenLive == 0:
                                    continue
                                liveWhen = dressWhen + 0.5 * whenLive
                                temptempattr[2]=liveWhen
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].append(temptempattr)
                                # print("temptempways=", temptempways)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney
                                    besttemptempway = copy.deepcopy(temptempways)
                                # print("besttemptempway=", besttemptempway)

                # print("besttemptempway=", besttemptempway)
                if besttemptempmoney>tempmoney:
                    tempways=copy.deepcopy(besttemptempway)
                    tempmoney=besttemptempmoney

                if tempmoney>bestbestmoney:
                    bestbestway = copy.deepcopy(tempways)  # way=[]情况下只需要保留这两个属性
                    bestbestmoney = besttemptempmoney  # way=[]情况下只需要保留这两个属性
            #这种情况下要以另一种思路插，故分开处理
            else:
                #考虑不化妆
                temptempattr = []
                temptempattr.append(0)
                temptempattr.append(0)
                temptempattr.append(0)
                temptempways = copy.deepcopy(ways)
                besttemptempmoney=-float("inf")
                besttemptempway=[]
                for everypos in range(len(way)+1):
                    if everypos==0:
                        if  way[everypos][2]>=14.5:
                            endtime=way[everypos][2] - 6.5
                            whenLive=begintime=8
                            while whenLive>=begintime and whenLive<=endtime:
                                temptempattr[2] = whenLive
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].insert(everypos,temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                    besttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                whenLive+=0.5
                        else:
                            continue
                    elif everypos==len(way):
                        if way[everypos - 1][2] <= 21.5:
                            whenLive = begintime = way[everypos - 1][2]+6.5
                            endtime = 21.5
                            while whenLive >= begintime and whenLive <= endtime:
                                temptempattr[2] = whenLive
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].insert(everypos,temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                    besttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                whenLive += 0.5
                        else:
                            continue
                    else:
                        if way[everypos][2] - way[everypos - 1][2] >= 6.5:
                            whenLive = begintime = way[everypos - 1][2] + 6.5
                            endtime = way[everypos][2] - 6.5
                            while whenLive >= begintime and whenLive <= endtime:
                                temptempattr[2] = whenLive
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].insert(everypos,temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                    besttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                whenLive += 0.5
                        else:
                            continue
                # print("bestway1:",besttemptempway)

                #考虑化妆
                bestbesttemptempmoney = -float("inf")
                bestbesttemptempway = []
                for whichone in range(dresserNumber):#遍历所有化妆师
                    for when in range(20):#遍历化妆师的所有工作时间结点
                        if when==10 or when==11:#避开化妆师午休时间
                            continue
                        dressWhen=7+0.5*when#化妆时间
                        temptempattr=[]
                        temptempattr.append(whichone+1)
                        temptempattr.append(dressWhen)
                        temptempattr.append(0)
                        if dressWhen==7.0:
                            for whenLive in range(10):
                                liveWhen=8+0.5*whenLive
                                temptempattr[2]=liveWhen

                                for everypos in range(len(way) + 1):
                                    if everypos == 0:
                                        if way[everypos][2] >= 14.5:
                                            endtime = way[everypos][2] - 6.5
                                            begintime = 8
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    elif everypos == len(way):
                                        if way[everypos - 1][2] <= 21.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = 21.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    else:
                                        if way[everypos][2] - way[everypos - 1][2] >= 6.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = way[everypos][2] - 6.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                        else:
                            for whenLive in range(11):
                                if whenLive==0:
                                    continue
                                liveWhen=dressWhen+0.5*whenLive
                                temptempattr[2]=liveWhen

                                for everypos in range(len(way) + 1):
                                    if everypos == 0:
                                        if way[everypos][2] >= 14.5:
                                            endtime = way[everypos][2] - 6.5
                                            begintime = 8
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    elif everypos == len(way):
                                        if way[everypos - 1][2] <= 21.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = 21.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    else:
                                        if way[everypos][2] - way[everypos - 1][2] >= 6.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = way[everypos][2] - 6.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue

                if bestbesttemptempmoney>besttemptempmoney:
                    besttemptempway=copy.deepcopy(bestbesttemptempway)
                    besttemptempmoney=bestbesttemptempmoney

                if besttemptempmoney>bestbestmoney:
                    bestbestway=copy.deepcopy(besttemptempway)
                    bestbestmoney=besttemptempmoney

            preHouse=way
        if bestbestway != []:
            ways = copy.deepcopy(bestbestway)
            pool -= 1
        else:
            print("在插入{}个主播时没有位置可以插入了，目前插了{}个主播，目前总收入为{}。开始使用ALNS算法进行动态调整".format(initialInfluencer,initialInfluencer-pool,moneySum(ways)))
            return ways,pool
    print("当你看到这条消息时说明你需要再进一步调大initialInfluencer的值，调大以后重开吧孩子，当前值为{}".format(initialInfluencer))
    return ways,pool


# 贪婪修复排班路径
def repairF1(ways, pool):# 贪婪重建算子
    for influencer in range(pool):  # 遍历每个主播
        if ((influencer+1)%10==0):
            print("="*30)
        bestbestway = []  # 记录每次插入最优的解
        bestbestmoney = -float("inf")  # 记录每次插入最优的收入

        for eachone in range(len(ways)):  # 遍历每个直播间
            way = ways[eachone]
            if eachone != 0:
                if way == [] and preHouse == []:  # 若当前播间为空，则后续也必定为空
                    break
            # 这种情况下可以以一种思路插
            if way == []:
                # 考虑不化妆直接插
                tempways = copy.deepcopy(ways)
                tempattr = []  # 主播的状态
                tempattr.append(0)
                tempattr.append(0)
                tempattr.append(8)
                tempways[eachone].append(tempattr)  # 记录不化妆情况下最好的插入路径
                tempmoney = moneySum(tempways)  # 记录不化妆情况下最好的插入收入
                # print("tempways=",tempways)

                # 考虑化完妆再插
                besttemptempway = []  # 记录化妆情况下最好的插入路径
                besttemptempmoney = -float("inf")  # 记录化妆情况下最好的插入收入
                for whichone in range(dresserNumber):  # 遍历所有化妆师
                    for when in range(20):  # 遍历化妆师的所有工作时间结点
                        if when == 10 or when == 11:  # 避开化妆师午休时间
                            continue
                        dressWhen = 7 + 0.5 * when  # 化妆时间
                        temptempattr = []
                        temptempattr.append(whichone + 1)
                        temptempattr.append(dressWhen)
                        temptempattr.append(0)
                        if dressWhen == 7.0:
                            for whenLive in range(10):
                                liveWhen = 8 + 0.5 * whenLive
                                temptempattr[2] = liveWhen
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].append(temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney
                                    besttemptempway = copy.deepcopy(temptempways)
                                # print("besttemptempway=", besttemptempway)
                        else:
                            for whenLive in range(11):
                                if whenLive == 0:
                                    continue
                                liveWhen = dressWhen + 0.5 * whenLive
                                temptempattr[2] = liveWhen
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].append(temptempattr)
                                # print("temptempways=", temptempways)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney
                                    besttemptempway = copy.deepcopy(temptempways)
                                # print("besttemptempway=", besttemptempway)

                # print("besttemptempway=", besttemptempway)
                if besttemptempmoney > tempmoney:
                    tempways = copy.deepcopy(besttemptempway)
                    tempmoney = besttemptempmoney

                if tempmoney > bestbestmoney:
                    bestbestway = copy.deepcopy(tempways)  # way=[]情况下只需要保留这两个属性
                    bestbestmoney = besttemptempmoney  # way=[]情况下只需要保留这两个属性
            # 这种情况下要以另一种思路插，故分开处理
            else:
                # 考虑不化妆
                temptempattr = []
                temptempattr.append(0)
                temptempattr.append(0)
                temptempattr.append(0)
                temptempways = copy.deepcopy(ways)
                besttemptempmoney = -float("inf")
                besttemptempway = []
                for everypos in range(len(way) + 1):
                    if everypos == 0:
                        if way[everypos][2] >= 14.5:
                            endtime = way[everypos][2] - 6.5
                            whenLive = begintime = 8
                            while whenLive >= begintime and whenLive <= endtime:
                                temptempattr[2] = whenLive
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].insert(everypos, temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                    besttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                whenLive += 0.5
                        else:
                            continue
                    elif everypos == len(way):
                        if way[everypos - 1][2] <= 21.5:
                            whenLive = begintime = way[everypos - 1][2] + 6.5
                            endtime = 21.5
                            while whenLive >= begintime and whenLive <= endtime:
                                temptempattr[2] = whenLive
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].insert(everypos, temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                    besttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                whenLive += 0.5
                        else:
                            continue
                    else:
                        if way[everypos][2] - way[everypos - 1][2] >= 6.5:
                            whenLive = begintime = way[everypos - 1][2] + 6.5
                            endtime = way[everypos][2] - 6.5
                            while whenLive >= begintime and whenLive <= endtime:
                                temptempattr[2] = whenLive
                                temptempways = copy.deepcopy(ways)
                                temptempways[eachone].insert(everypos, temptempattr)
                                temptempmoney = moneySum(temptempways)
                                if temptempmoney > besttemptempmoney:
                                    besttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                    besttemptempway = copy.deepcopy(temptempways)  # way！=[]情况下只需要保留这两个属性
                                whenLive += 0.5
                        else:
                            continue
                # print("bestway1:",besttemptempway)

                # 考虑化妆
                bestbesttemptempmoney = -float("inf")
                bestbesttemptempway = []
                for whichone in range(dresserNumber):  # 遍历所有化妆师
                    for when in range(20):  # 遍历化妆师的所有工作时间结点
                        if when == 10 or when == 11:  # 避开化妆师午休时间
                            continue
                        dressWhen = 7 + 0.5 * when  # 化妆时间
                        temptempattr = []
                        temptempattr.append(whichone + 1)
                        temptempattr.append(dressWhen)
                        temptempattr.append(0)
                        if dressWhen == 7.0:
                            for whenLive in range(10):
                                liveWhen = 8 + 0.5 * whenLive
                                temptempattr[2] = liveWhen

                                for everypos in range(len(way) + 1):
                                    if everypos == 0:
                                        if way[everypos][2] >= 14.5:
                                            endtime = way[everypos][2] - 6.5
                                            begintime = 8
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(
                                                        temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    elif everypos == len(way):
                                        if way[everypos - 1][2] <= 21.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = 21.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(
                                                        temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    else:
                                        if way[everypos][2] - way[everypos - 1][2] >= 6.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = way[everypos][2] - 6.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(
                                                        temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                        else:
                            for whenLive in range(11):
                                if whenLive == 0:
                                    continue
                                liveWhen = dressWhen + 0.5 * whenLive
                                temptempattr[2] = liveWhen

                                for everypos in range(len(way) + 1):
                                    if everypos == 0:
                                        if way[everypos][2] >= 14.5:
                                            endtime = way[everypos][2] - 6.5
                                            begintime = 8
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(
                                                        temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    elif everypos == len(way):
                                        if way[everypos - 1][2] <= 21.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = 21.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(
                                                        temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue
                                    else:
                                        if way[everypos][2] - way[everypos - 1][2] >= 6.5:
                                            begintime = way[everypos - 1][2] + 6.5
                                            endtime = way[everypos][2] - 6.5
                                            if liveWhen >= begintime and liveWhen <= endtime:
                                                temptempways = copy.deepcopy(ways)
                                                temptempways[eachone].insert(everypos, temptempattr)
                                                temptempmoney = moneySum(temptempways)
                                                if temptempmoney > bestbesttemptempmoney:
                                                    bestbesttemptempmoney = temptempmoney  # way！=[]情况下只需要保留这两个属性
                                                    bestbesttemptempway = copy.deepcopy(
                                                        temptempways)  # way！=[]情况下只需要保留这两个属性
                                        else:
                                            continue

                if bestbesttemptempmoney > besttemptempmoney:
                    besttemptempway = copy.deepcopy(bestbesttemptempway)
                    besttemptempmoney = bestbesttemptempmoney

                if besttemptempmoney > bestbestmoney:
                    bestbestway = copy.deepcopy(besttemptempway)
                    bestbestmoney = besttemptempmoney

            preHouse = way
        if bestbestway != []:
            ways = copy.deepcopy(bestbestway)
            pool -= 1
        else:
            print("在插入{}个主播时没有位置可以插入了，目前共有{}个主播并且收入为{}".format(pool, gettotal(ways),moneySum(ways)))
            return ways, pool
    print("成功插入，我在repairF1里面，目前共有{}个主播并且收入为{}".format(gettotal(ways),moneySum(ways)))
    return ways, pool


# 随机摧毁排班路径
def destroyF1(ways, step):  # 随机摧毁算子
    pool = 0  # 记录被摧毁的直播数
    for i in range(step):
        if ways==[]:
            break
        index1 = random.randint(0, len(ways) - 1)
        while len(ways[index1]) == 0:
            index1 = random.randint(0, len(ways) - 1)
        index2 = random.randint(0, len(ways[index1]) - 1)
        del ways[index1][index2]
        pool += 1
    if step==pool:
        pass
    else:
        print("destroyF1犯病了")
    return ways, pool


# 贪婪摧毁排班路径
# def destroyF2(ways, step):
#     sorted_ways = sorted(ways, key=len)
#     total = len(sorted_ways)
#     to_remove = []
#     to_remove1 = sorted_ways[:(step // 2)]
#     for item in to_remove1:
#         to_remove.append(item)
#     to_remove2 = sorted_ways[(total - (step - step // 2)):]
#     for item in to_remove2:
#         to_remove.append(item)
#     new_list = [i for i in ways if i not in to_remove]
#     count = 0
#     for item in to_remove:
#         count += len(item)
#     return new_list, count


# 用于计算收入


def moneySum(ways, printf=False):

    #各种损失和目标函数
    payback=0
    noonbreakLoss=0 #保证中午午休一个小时
    dresserLoss=0 # 保证化妆师的工作安排是合理的，即每个工作时间间隔要保证至少大于30分钟 #硬约束
    workingLoss=0 #保证一天工作6.5小时  #硬约束
    ratioLoss=0
    workingNumber=0
    dressedInfluencerNumber=0
    averageLoss = 0

    #化妆师的安排
    dresserArrangement=[]
    for _ in range(dresserNumber):
        dresserArrangement.append([])

    #计算loss过程
    for way in ways:
        for point in way: #每个point大概为[a,b,c]：a为哪个化妆师化的妆，若没化则为0；b为化妆时间，若未画则为0；c为开始工作时间
            #统计主播数量
            workingNumber+=1

            if point[0]!=0:
                dressedInfluencerNumber+=1
                # 这里在把每一个需要化妆的人添加到化妆师的安排中，统计完成后在lossfun的末尾计算noonbreakLoss以及dresserLoss
                dresserArrangement[point[0]-1].append(point[1])
            #在计算workingLoss
            if point==way[0]:
                preWorkingTime=point[2]
            else:
                # print("pre:", preWorkingTime)
                # print("now:", point[2])
                if point[2]-preWorkingTime<6.5:
                    workingLoss+=1
                preWorkingTime=point[2]
    #在这里尝试计算noonbreakLoss以及dresserLoss
    # print(dresserArrangement)
    for each in dresserArrangement:#each为每一个dresser的安排
        each.sort()
        # print(each)
        for eachies in range(len(each)):#eachies为安排结点
            eachdresser=each[eachies]
            if eachies==0:
                preWorkTime=eachdresser
            else:
                if eachdresser-preWorkTime<0.5:
                    dresserLoss+=1
                preWorkTime=eachdresser
            if eachdresser>12.0 and eachdresser<13.0:
                noonbreakLoss+=1

    #计算ratioLoss
    if dressedInfluencerNumber/workingNumber < 1:
        ratioLoss+=1

    #计算averageLoss
    sig=getdifference(dresserArrangement)
    if sig:
        averageLoss+=1

    #计算奖惩大小
    wage=4000
    payback=wage*workingNumber
    penalty=1e9#为dresserLoss、noonbreakLoss以及waitingLoss服务
    loss = penalty * dresserLoss + penalty * workingLoss + penalty * noonbreakLoss + penalty * ratioLoss+penalty*averageLoss
    # print(dresserLoss)
    # print(workingLoss)
    # print(noonbreakLoss)
    # print(ratioLoss)
    return payback-loss


def moneySumTrue(ways, printf=False):

    #各种损失和目标函数
    payback=0
    noonbreakLoss=0 #保证中午午休一个小时
    dresserLoss=0 # 保证化妆师的工作安排是合理的，即每个工作时间间隔要保证至少大于30分钟 #硬约束
    workingLoss=0 #保证一天工作6.5小时  #硬约束
    ratioLoss=0
    workingNumber=0
    dressedInfluencerNumber=0
    averageLoss=0

    #化妆师的安排
    dresserArrangement=[]
    for _ in range(dresserNumber):
        dresserArrangement.append([])

    #计算loss过程
    for way in ways:
        for point in way: #每个point大概为[a,b,c]：a为哪个化妆师化的妆，若没化则为0；b为化妆时间，若未画则为0；c为开始工作时间
            #统计主播数量
            workingNumber+=1

            if point[0]!=0:
                dressedInfluencerNumber+=1
                # 这里在把每一个需要化妆的人添加到化妆师的安排中，统计完成后在lossfun的末尾计算noonbreakLoss以及dresserLoss
                dresserArrangement[point[0]-1].append(point[1])
            #在计算workingLoss
            if point==way[0]:
                preWorkingTime=point[2]
            else:
                # print("pre:", preWorkingTime)
                # print("now:", point[2])
                if point[2]-preWorkingTime<6.5:
                    workingLoss+=1
                preWorkingTime=point[2]
    #在这里尝试计算noonbreakLoss以及dresserLoss
    # print(dresserArrangement)
    for each in dresserArrangement:#each为每一个dresser的安排
        each.sort()
        # print(each)
        for eachies in range(len(each)):#eachies为安排结点
            eachdresser=each[eachies]
            if eachies==0:
                preWorkTime=eachdresser
            else:
                if eachdresser-preWorkTime<0.5:
                    dresserLoss+=1
                preWorkTime=eachdresser
            if eachdresser>12.0 and eachdresser<13.0:
                noonbreakLoss+=1

    #计算ratioLoss
    if dressedInfluencerNumber/workingNumber < 1:
        ratioLoss+=1

    #计算averageLoss
    sig = getdifference(dresserArrangement)
    if sig:
        averageLoss += 1

    #计算奖惩大小
    wage=4000
    dressedWage=4800
    payback=wage*(workingNumber-dressedInfluencerNumber)+dressedWage*dressedInfluencerNumber
    penalty=1e9#为dresserLoss、noonbreakLoss以及waitingLoss服务
    loss = penalty * dresserLoss + penalty * workingLoss + penalty * noonbreakLoss + penalty * ratioLoss +penalty*averageLoss
    # print(dresserLoss)
    # print(workingLoss)
    # print(noonbreakLoss)
    # print(ratioLoss)
    return payback-loss


def getdifference(arrangement):
    lengths = [len(sublist) for sublist in arrangement]

    # 如果列表数量少于2，直接返回0
    if len(lengths) < 2:
        return 0

    # 计算最大长度和最小长度
    max_length = max(lengths)
    min_length = min(lengths)

    # 如果最大长度和最小长度的差大于1，则存在两个列表长度差超过1
    if max_length - min_length > 1:
        return 1
    else:
        return 0


def gettotal(ways):
    workingNumber = 0
    # 计算loss过程
    for way in ways:
        for point in way:  # 每个point大概为[a,b,c]：a为哪个化妆师化的妆，若没化则为0；b为化妆时间，若未画则为0；c为开始工作时间
            # 统计主播数量
            workingNumber += 1
    return workingNumber


def getdress(ways, printf=False):

    dressedInfluencerNumber=0

    for way in ways:
        for point in way: #每个point大概为[a,b,c]：a为哪个化妆师化的妆，若没化则为0；b为化妆时间，若未画则为0；c为开始工作时间
            if point[0]!=0:
                dressedInfluencerNumber+=1
    return dressedInfluencerNumber


# 程序最初开始执行的地方
loss = list()
Bsolution = list()
current_loss = list()
loss_list = list()


# 设置配置信息
liveHouseNumber= 75  # 直播间数量为75
influencerNumber=50 # 主播数量为50
dresserNumber=15 # 化妆师数量为7
initialInfluencer=180

# 构建解的框架
ways = []
for i in range(liveHouseNumber):  # liveHouseNumber为直播间数量
    ways.append([])
# 生成初始解
time_1=time.time()
ways,pool=genF(ways,initialInfluencer)
# ways=[[[1, 7.0, 8.0], [1, 9.5, 14.5], [0, 0, 21.0]], [[1, 7.5, 8.0], [0, 0, 14.5], [1, 16.0, 21.0]], [[1, 8.5, 9.0], [1, 16.5, 21.5]], [[0, 0, 8], [1, 10.0, 14.5], [2, 16.0, 21.0]], [[0, 0, 8], [1, 10.5, 14.5], [0, 0, 21.0]], [[0, 0, 8], [1, 11.0, 15.5]], [[1, 8.0, 8.5], [0, 0, 15.0], [2, 16.5, 21.5]], [[0, 0, 8], [1, 13.0, 14.5], [3, 16.5, 21.0]], [[0, 0, 8], [1, 13.5, 14.5], [0, 0, 21.0]], [[2, 7.0, 8.0], [1, 11.5, 14.5], [0, 0, 21.0]], [[0, 0, 8], [1, 15.0, 15.5]], [[1, 9.0, 9.5], [0, 0, 16.0]], [[0, 0, 8], [1, 15.5, 16.0]], [[2, 7.5, 8.0], [2, 9.5, 14.5], [0, 0, 21.0]], [[2, 8.0, 8.5], [0, 0, 15.0], [4, 16.5, 21.5]], [[0, 0, 8], [1, 14.0, 14.5], [6, 16.5, 21.0]], [[3, 7.0, 8.0], [1, 14.5, 15.0], [0, 0, 21.5]], [[2, 10.0, 10.5], [0, 0, 17.0]], [[0, 0, 8], [2, 10.5, 14.5], [4, 16.0, 21.0]], [[0, 0, 8], [2, 13.5, 18.0]], [[0, 0, 8], [2, 11.5, 14.5], [0, 0, 21.0]], [[3, 7.5, 8.0], [2, 14.0, 14.5], [5, 16.5, 21.0]], [[0, 0, 8], [0, 0, 14.5], [6, 16.0, 21.0]], [[5, 7.5, 8.0], [2, 11.0, 14.5], [0, 0, 21.0]], [[2, 13.0, 13.5], [3, 15.0, 20.0]], [[2, 8.5, 9.0], [2, 15.0, 15.5]], [[4, 8.0, 8.5], [0, 0, 15.0], [7, 16.5, 21.5]], [[3, 8.5, 9.0], [0, 0, 15.5]], [[6, 8.0, 8.5], [2, 14.5, 15.0], [0, 0, 21.5]], [[3, 9.0, 9.5], [3, 13.0, 17.0]], [[0, 0, 8], [0, 0, 14.5], [0, 0, 21.0]], [[3, 10.0, 10.5], [3, 13.5, 18.0]], [[0, 0, 8], [2, 15.5, 16.0]], [[0, 0, 8], [3, 14.0, 14.5], [3, 16.0, 21.0]], [[0, 0, 8], [3, 9.5, 14.5], [0, 0, 21.0]], [[3, 8.0, 8.5], [3, 10.5, 15.0], [0, 0, 21.5]], [[0, 0, 8], [3, 11.0, 14.5], [0, 0, 21.0]], [[4, 7.0, 8.0], [4, 9.5, 14.5], [0, 0, 21.0]], [[4, 7.5, 8.0], [0, 0, 14.5], [0, 0, 21.0]], [[3, 11.5, 12.0], [0, 0, 21.5]], [[0, 0, 8], [4, 10.0, 14.5], [5, 16.0, 21.0]], [[6, 7.0, 8.0], [4, 10.5, 14.5], [0, 0, 21.0]], [[4, 8.5, 9.0], [3, 14.5, 15.5]], [[0, 0, 8], [4, 11.5, 14.5], [0, 0, 21.0]], [[2, 9.0, 9.5], [0, 0, 16.0]], [[0, 0, 8], [4, 13.5, 14.5], [0, 0, 21.0]], [[5, 7.0, 8.0], [4, 13.0, 14.5], [0, 0, 21.0]], [[0, 0, 8], [4, 14.0, 14.5], [0, 0, 21.5]], [[5, 8.5, 9.0], [4, 15.0, 15.5]], [[4, 9.0, 9.5], [3, 15.5, 16.0]], [[5, 8.0, 8.5], [5, 10.0, 15.0], [0, 0, 21.5]], [[0, 0, 8], [4, 11.0, 14.5], [0, 0, 21.0]], [[5, 9.0, 9.5], [4, 14.5, 16.0]], [[0, 0, 8], [5, 9.5, 14.5], [0, 0, 21.0]], [[0, 0, 8], [4, 15.5, 16.0]], [[0, 0, 8], [5, 10.5, 14.5], [0, 0, 21.0]], [[5, 11.0, 11.5], [5, 13.5, 18.0]], [[0, 0, 8], [5, 13.0, 14.5], [0, 0, 21.0]], [[0, 0, 8], [5, 14.5, 15.0], [0, 0, 21.5]], [[6, 8.5, 9.0], [5, 15.0, 15.5]], [[6, 7.5, 8.0], [5, 11.5, 14.5], [0, 0, 21.0]], [[0, 0, 8], [5, 14.0, 14.5], [0, 0, 21.0]], [[6, 9.0, 9.5], [6, 11.5, 16.0]], [[7, 8.5, 9.0], [5, 15.5, 16.0]], [[6, 9.5, 10.0], [0, 0, 16.5]], [[0, 0, 8], [6, 11.0, 14.5], [0, 0, 21.0]], [[6, 10.0, 10.5], [6, 13.0, 17.0]], [[0, 0, 8], [6, 14.0, 14.5], [0, 0, 21.0]], [[7, 7.0, 8.0], [6, 14.5, 15.0], [0, 0, 21.5]], [[6, 10.5, 11.0], [0, 0, 17.5]], [[7, 7.5, 8.0], [6, 15.5, 16.0]], [[0, 0, 8], [7, 10.5, 14.5], [0, 0, 21.0]], [[7, 9.5, 14.5], [7, 16.0, 21.0]], [[6, 13.5, 14.0], [7, 15.5, 20.5]], [[7, 8.0, 8.5], [7, 10.0, 15.0], [0, 0, 21.5]]]
# pool=5
initialSolution=copy.deepcopy(ways)
time_2=time.time()
print("生成初始解用时为：",time_2-time_1)
print("初始解中主播的总数为{}，总收入为{}，未化妆主播数量{}，化妆主播数量{}".format(gettotal(ways),moneySum(ways),gettotal(ways)-getdress(ways),getdress(ways)))


# 算法参数设置
T = 100  # 初始温度
a = 0.98  # 退火系数
b = 0.5 #得分权重
iterxMax = 10  # 最大迭代次数
countMax = 5  # 最优解多少次没有更新就停止迭代
counter = 0  # 用于记录最优解几次没有更新了
stepF = int(0.4*(initialInfluencer-pool))
stepbystep=1
timer=0

wDestroyF = [1 for i in range(1)]  # [1,1] # weights of the destroy operators  #摧毁算子的权重
wRepairF = [1 for i in range(1)]  # [1,1] # weights of the repair operators #修复算子的权重
destroyUseTimesF = [0 for i in range(1)]  # [0,0] #The number of times the destroy operator has been used #摧毁算子的使用次数
repairUseTimesF = [0 for i in range(1)]  # [0,0] #The number of times the repair operator has been used #修复算子的使用次数
destroyScoreF = [1 for i in range(1)]  # [1,1] # the score of destroy operators #摧毁算子的得分
repairScoreF = [1 for i in range(1)]  # [1,1] # the score of repair operators #修复算子的得分

solution = copy.deepcopy(ways)  # initial solution
loss.append(moneySum(solution))
bestSolution = copy.deepcopy(ways)
Bsolution.append(solution)
############################################
############ 动态调整插入的主播数量 ############
############################################

iterx = 0
while iterx < iterxMax:  # while stop criteria not met
    print("----------------------------------------------------------------")
    print("正在进行第", iterx + 1, "次迭代，共", iterxMax, "次")
    print("----------------------------------------------------------------")
    while T > 10:
        if gettotal(solution)<(initialInfluencer//2):
            print("===============重启ALNS===============")
            ways=copy.deepcopy(initialSolution)
        destroyedSolution, remove, destroyOperatorIndexF = selectAndUseDestroyOperator(wDestroyF, solution, stepF)
        remove+=stepbystep
        print("remove从{}动态调整为{}".format(remove-stepbystep,remove))
        if destroyedSolution==[]:
            continue
        newSolution, repairOperatorIndexF, remove = selectAndUseRepairOperator(wRepairF, destroyedSolution, remove)
        if remove!=0:
            print("未成功插入，重新开始调整")
        else:
            print("成功插入，我在主函数里面")
        # 更新权重、得分
        if moneySum(newSolution) >= moneySum(solution):
            solution = copy.deepcopy(newSolution)
            if moneySum(newSolution) >= moneySum(bestSolution):
                bestSolution = copy.deepcopy(newSolution)

                destroyScoreF[destroyOperatorIndexF] += 1.5  # update the score of the operators
                repairScoreF[repairOperatorIndexF] += 1.5
            else:
                destroyScoreF[destroyOperatorIndexF] += 1.2
                repairScoreF[repairOperatorIndexF] += 1.2

        # 不再接收差的解
        # else:
        #     if random.random() < np.exp((moneySum(newSolution) + moneySum(solution)) / abs(moneySum(newSolution))):  # the simulated annealing acceptance criteria
        #
        #         solution = copy.deepcopy(newSolution)
        #         destroyScoreF[destroyOperatorIndexF] += 0.8
        #         repairScoreF[repairOperatorIndexF] += 0.8
        #
        #     else:
        #         destroyScoreF[destroyOperatorIndexF] += 0.6
        #         repairScoreF[repairOperatorIndexF] += 0.6

        loss_list.append(moneySum(solution))

        wDestroyF[destroyOperatorIndexF] = wDestroyF[destroyOperatorIndexF] * b + (1 - b) * (destroyScoreF[destroyOperatorIndexF] / destroyUseTimesF[destroyOperatorIndexF])
        wRepairF[repairOperatorIndexF] = wRepairF[repairOperatorIndexF] * b + (1 - b) * (repairScoreF[repairOperatorIndexF] / repairUseTimesF[repairOperatorIndexF])
        # update the weight of the operators

        if timer==0:
            prebest=copy.deepcopy(bestSolution)
            timer+=1
        else:
            if bestSolution==prebest:
                counter+=1
            if counter > countMax:  # “最优解是第几次不改变值”的次数到达阈值就结束程序
                print("----------------------------------------------------------------")
                print("已经{}次没有更新过最优解了，提前终止程序".format(countMax))
                print("----------------------------------------------------------------")
                iterx = iterxMax
                break
            prebest = copy.deepcopy(bestSolution)

        print("当前最优解为{}".format(bestSolution))
        print("插入总数为{}，收入为{}".format(gettotal(bestSolution), moneySum(bestSolution)))

        T = a * T
    iterx += 1
    T = 100

Bsolution.append(bestSolution)
loss.append(loss_list)
time_3=time.time()
print("最终结果如下：")
print("排班表为：",bestSolution)
print("最终收入为：",moneySumTrue(bestSolution)-15*9000)
print("最终插入了{}个主播，其中化妆的有{}，未化妆的有{}".format(gettotal(bestSolution),getdress(bestSolution),gettotal(ways)-getdress(ways)))
print("ALNS算法耗时{}".format(time_3-time_2))

print(loss)
print(loss[0])
print(loss[1])

# 迭代最优解迭代过程画图
plt.figure(figsize=(10, 10))
plt.hlines(xmin=0, xmax=len(loss[1])-1, y=loss[0], colors="g")
plt.plot(loss[1], 'r')
plt.legend(['initial', 'final'])
plt.xlabel('epoch')
plt.ylabel('general income')
plt.savefig('1_1/1_1_1.png', dpi=1800)
plt.show()